package com.harmony.pilot.completion.lsp;

import com.harmony.pilot.common.dto.*;
import com.harmony.pilot.completion.service.CompletionService;
import com.harmony.pilot.completion.service.DiagnosticService;
import com.harmony.pilot.completion.service.NavigationService;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.lsp4j.*;
import org.eclipse.lsp4j.jsonrpc.messages.Either;
import org.eclipse.lsp4j.services.LanguageClient;
import org.eclipse.lsp4j.services.LanguageClientAware;
import org.eclipse.lsp4j.services.LanguageServer;
import org.eclipse.lsp4j.services.TextDocumentService;
import org.eclipse.lsp4j.services.WorkspaceService;

import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

/**
 * OpenHarmony Language Server
 * 实现Language Server Protocol，提供代码补全、导航、诊断等功能
 */
@Slf4j
public class OpenHarmonyLanguageServer implements LanguageServer, LanguageClientAware {
    
    private final CompletionService completionService;
    private final NavigationService navigationService;
    private final DiagnosticService diagnosticService;
    
    private LanguageClient languageClient;
    private final Map<String, TextDocumentItem> documents = new HashMap<>();
    
    public OpenHarmonyLanguageServer(
            CompletionService completionService,
            NavigationService navigationService,
            DiagnosticService diagnosticService) {
        this.completionService = completionService;
        this.navigationService = navigationService;
        this.diagnosticService = diagnosticService;
    }
    
    @Override
    public CompletableFuture<InitializeResult> initialize(InitializeParams params) {
        log.info("Initializing Language Server");
        
        ServerCapabilities capabilities = new ServerCapabilities();
        
        // 文本同步能力
        capabilities.setTextDocumentSync(TextDocumentSyncKind.Incremental);
        
        // 补全能力
        CompletionOptions completionOptions = new CompletionOptions();
        completionOptions.setTriggerCharacters(Arrays.asList(".", "::", "->", "("));
        completionOptions.setResolveProvider(true);
        capabilities.setCompletionProvider(completionOptions);
        
        // 跳转到定义能力
        capabilities.setDefinitionProvider(Boolean.TRUE);
        
        // 查找引用能力
        capabilities.setReferencesProvider(Boolean.TRUE);
        
        // 查找实现能力
        capabilities.setImplementationProvider(Boolean.TRUE);
        
        // 悬停提示能力
        capabilities.setHoverProvider(Boolean.TRUE);
        
        // 文档符号能力
        capabilities.setDocumentSymbolProvider(Boolean.TRUE);
        
        // 工作区符号能力
        capabilities.setWorkspaceSymbolProvider(Boolean.TRUE);
        
        // 诊断能力
        capabilities.setDiagnosticProvider(new DiagnosticOptions(true));
        
        // 代码操作能力（Code Actions）
        capabilities.setCodeActionProvider(Boolean.TRUE);
        
        // 代码格式化能力
        DocumentFormattingOptions formatOptions = new DocumentFormattingOptions();
        formatOptions.setFormatOnSave(Boolean.TRUE);
        capabilities.setDocumentFormattingProvider(Boolean.TRUE);
        
        InitializeResult result = new InitializeResult(capabilities);
        return CompletableFuture.completedFuture(result);
    }
    
    @Override
    public CompletableFuture<Object> shutdown() {
        log.info("Shutting down Language Server");
        return CompletableFuture.completedFuture(null);
    }
    
    @Override
    public void exit() {
        log.info("Language Server exited");
        System.exit(0);
    }
    
    @Override
    public TextDocumentService getTextDocumentService() {
        return new OpenHarmonyTextDocumentService();
    }
    
    @Override
    public WorkspaceService getWorkspaceService() {
        return new OpenHarmonyWorkspaceService();
    }
    
    @Override
    public void connect(LanguageClient client) {
        this.languageClient = client;
        log.info("Language Client connected");
    }
    
    /**
     * 文本文档服务实现
     */
    private class OpenHarmonyTextDocumentService implements TextDocumentService {
        
        @Override
        public void didOpen(DidOpenTextDocumentParams params) {
            TextDocumentItem document = params.getTextDocument();
            documents.put(document.getUri(), document);
            log.debug("Document opened: {}", document.getUri());
            
            // 发送诊断
            publishDiagnostics(document.getUri(), document.getText());
        }
        
        @Override
        public void didChange(DidChangeTextDocumentParams params) {
            TextDocumentItem document = documents.get(params.getTextDocument().getUri());
            if (document == null) {
                return;
            }
            
            // 应用增量更新
            for (TextDocumentContentChangeEvent change : params.getContentChanges()) {
                if (change.getRange() != null) {
                    // 增量更新
                    applyIncrementalChange(document, change);
                } else {
                    // 全量更新
                    document.setText(change.getText());
                }
            }
            
            log.debug("Document changed: {}", params.getTextDocument().getUri());
            
            // 发送诊断
            publishDiagnostics(document.getUri(), document.getText());
        }
        
        @Override
        public void didClose(DidCloseTextDocumentParams params) {
            documents.remove(params.getTextDocument().getUri());
            log.debug("Document closed: {}", params.getTextDocument().getUri());
            
            // 清除诊断
            if (languageClient != null) {
                languageClient.publishDiagnostics(new PublishDiagnosticsParams(
                    params.getTextDocument().getUri(),
                    Collections.emptyList()
                ));
            }
        }
        
        @Override
        public void didSave(DidSaveTextDocumentParams params) {
            log.debug("Document saved: {}", params.getTextDocument().getUri());
        }
        
        @Override
        public CompletableFuture<Either<List<CompletionItem>, CompletionList>> completion(
                CompletionParams params) {
            
            log.debug("Completion request for: {}", params.getPosition());
            
            try {
                TextDocumentItem document = documents.get(params.getTextDocument().getUri());
                if (document == null) {
                    return CompletableFuture.completedFuture(
                        Either.forRight(new CompletionList(false, Collections.emptyList()))
                    );
                }
                
                // 构建请求
                CompletionRequest request = buildCompletionRequest(document, params);
                
                // 调用补全服务
                List<com.harmony.pilot.common.dto.CompletionItem> items = 
                    completionService.getCompletions(request);
                
                // 转换为LSP格式
                List<CompletionItem> lspItems = items.stream()
                    .map(this::convertToLSPCompletionItem)
                    .collect(Collectors.toList());
                
                CompletionList completionList = new CompletionList(false, lspItems);
                return CompletableFuture.completedFuture(Either.forRight(completionList));
                
            } catch (Exception e) {
                log.error("Failed to get completions", e);
                return CompletableFuture.completedFuture(
                    Either.forRight(new CompletionList(false, Collections.emptyList()))
                );
            }
        }
        
        @Override
        public CompletableFuture<CompletionItem> resolveCompletionItem(CompletionItem unresolved) {
            // 可以在这里解析补全项的详细信息
            return CompletableFuture.completedFuture(unresolved);
        }
        
        @Override
        public CompletableFuture<Either<List<? extends Location>, List<? extends LocationLink>>> definition(
                DefinitionParams params) {
            
            log.debug("Definition request for: {}", params.getPosition());
            
            try {
                TextDocumentItem document = documents.get(params.getTextDocument().getUri());
                if (document == null) {
                    return CompletableFuture.completedFuture(Either.forLeft(Collections.emptyList()));
                }
                
                // 获取符号名称
                String symbol = extractSymbolAtPosition(document, params.getPosition());
                if (symbol == null || symbol.isEmpty()) {
                    return CompletableFuture.completedFuture(Either.forLeft(Collections.emptyList()));
                }
                
                // 构建上下文
                CodeContext context = buildCodeContext(document);
                
                // 调用导航服务
                Location location = navigationService.goToDefinition(symbol, context);
                
                if (location == null) {
                    return CompletableFuture.completedFuture(Either.forLeft(Collections.emptyList()));
                }
                
                // 转换为LSP格式
                org.eclipse.lsp4j.Location lspLocation = convertToLSPLocation(location);
                return CompletableFuture.completedFuture(
                    Either.forLeft(Collections.singletonList(lspLocation))
                );
                
            } catch (Exception e) {
                log.error("Failed to find definition", e);
                return CompletableFuture.completedFuture(Either.forLeft(Collections.emptyList()));
            }
        }
        
        @Override
        public CompletableFuture<List<? extends Location>> references(ReferenceParams params) {
            
            log.debug("References request for: {}", params.getPosition());
            
            try {
                TextDocumentItem document = documents.get(params.getTextDocument().getUri());
                if (document == null) {
                    return CompletableFuture.completedFuture(Collections.emptyList());
                }
                
                // 获取符号名称
                String symbol = extractSymbolAtPosition(document, params.getPosition());
                if (symbol == null || symbol.isEmpty()) {
                    return CompletableFuture.completedFuture(Collections.emptyList());
                }
                
                // 构建上下文
                CodeContext context = buildCodeContext(document);
                
                // 调用导航服务
                List<com.harmony.pilot.common.dto.Location> locations = 
                    navigationService.findReferences(symbol, context);
                
                // 转换为LSP格式
                List<org.eclipse.lsp4j.Location> lspLocations = locations.stream()
                    .map(this::convertToLSPLocation)
                    .collect(Collectors.toList());
                
                return CompletableFuture.completedFuture(lspLocations);
                
            } catch (Exception e) {
                log.error("Failed to find references", e);
                return CompletableFuture.completedFuture(Collections.emptyList());
            }
        }
        
        @Override
        public CompletableFuture<Either<List<? extends Location>, List<? extends LocationLink>>> implementation(
                ImplementationParams params) {
            
            log.debug("Implementation request for: {}", params.getPosition());
            
            try {
                TextDocumentItem document = documents.get(params.getTextDocument().getUri());
                if (document == null) {
                    return CompletableFuture.completedFuture(Either.forLeft(Collections.emptyList()));
                }
                
                // 获取符号名称
                String symbol = extractSymbolAtPosition(document, params.getPosition());
                if (symbol == null || symbol.isEmpty()) {
                    return CompletableFuture.completedFuture(Either.forLeft(Collections.emptyList()));
                }
                
                // 构建上下文
                CodeContext context = buildCodeContext(document);
                
                // 调用导航服务
                List<com.harmony.pilot.common.dto.Location> locations = 
                    navigationService.findImplementations(symbol, context);
                
                // 转换为LSP格式
                List<org.eclipse.lsp4j.Location> lspLocations = locations.stream()
                    .map(this::convertToLSPLocation)
                    .collect(Collectors.toList());
                
                return CompletableFuture.completedFuture(Either.forLeft(lspLocations));
                
            } catch (Exception e) {
                log.error("Failed to find implementations", e);
                return CompletableFuture.completedFuture(Either.forLeft(Collections.emptyList()));
            }
        }
        
        @Override
        public CompletableFuture<Hover> hover(HoverParams params) {
            
            log.debug("Hover request for: {}", params.getPosition());
            
            try {
                TextDocumentItem document = documents.get(params.getTextDocument().getUri());
                if (document == null) {
                    return CompletableFuture.completedFuture(null);
                }
                
                // 获取符号名称
                String symbol = extractSymbolAtPosition(document, params.getPosition());
                if (symbol == null || symbol.isEmpty()) {
                    return CompletableFuture.completedFuture(null);
                }
                
                // 构建上下文
                CodeContext context = buildCodeContext(document);
                
                // 查找定义以获取详细信息
                Location location = navigationService.goToDefinition(symbol, context);
                
                Hover hover = new Hover();
                MarkupContent content = new MarkupContent();
                content.setKind("markdown");
                
                if (location != null) {
                    content.setValue("**" + symbol + "**\n\n定义位置: " + location.getFilePath() + 
                        ":" + location.getLine());
                } else {
                    content.setValue("**" + symbol + "**\n\n未找到定义");
                }
                
                hover.setContents(Either.forLeft(content));
                return CompletableFuture.completedFuture(hover);
                
            } catch (Exception e) {
                log.error("Failed to get hover", e);
                return CompletableFuture.completedFuture(null);
            }
        }
        
        @Override
        public CompletableFuture<List<? extends DocumentSymbol>> documentSymbol(
                DocumentSymbolParams params) {
            
            // 可以返回文档中的所有符号
            return CompletableFuture.completedFuture(Collections.emptyList());
        }
        
        @Override
        public CompletableFuture<List<Either<Command, CodeAction>>> codeAction(CodeActionParams params) {
            
            // 可以返回代码操作建议
            return CompletableFuture.completedFuture(Collections.emptyList());
        }
        
        @Override
        public CompletableFuture<List<? extends TextEdit>> formatting(DocumentFormattingParams params) {
            
            // 可以返回格式化建议
            return CompletableFuture.completedFuture(Collections.emptyList());
        }
        
        // 辅助方法
        
        private CompletionRequest buildCompletionRequest(TextDocumentItem document, CompletionParams params) {
            Position position = params.getPosition();
            
            CodeContext context = new CodeContext();
            context.setFilePath(uriToFilePath(document.getUri()));
            context.setCode(document.getText());
            context.setCursorLine(position.getLine());
            context.setCursorColumn(position.getCharacter());
            
            CompletionRequest request = new CompletionRequest();
            request.setContext(context);
            request.setUseLLM(true);
            request.setMaxResults(50);
            
            return request;
        }
        
        private CodeContext buildCodeContext(TextDocumentItem document) {
            CodeContext context = new CodeContext();
            context.setFilePath(uriToFilePath(document.getUri()));
            context.setCode(document.getText());
            return context;
        }
        
        private String extractSymbolAtPosition(TextDocumentItem document, Position position) {
            // 简化实现：从当前位置提取符号
            String[] lines = document.getText().split("\n");
            if (position.getLine() >= lines.length) {
                return null;
            }
            
            String line = lines[position.getLine()];
            int column = position.getCharacter();
            
            // 向前查找符号开始
            int start = column;
            while (start > 0 && Character.isJavaIdentifierPart(line.charAt(start - 1))) {
                start--;
            }
            
            // 向后查找符号结束
            int end = column;
            while (end < line.length() && Character.isJavaIdentifierPart(line.charAt(end))) {
                end++;
            }
            
            if (start < end) {
                return line.substring(start, end);
            }
            
            return null;
        }
        
        private void applyIncrementalChange(TextDocumentItem document, TextDocumentContentChangeEvent change) {
            String[] lines = document.getText().split("\n", -1);
            Range range = change.getRange();
            
            int startLine = range.getStart().getLine();
            int endLine = range.getEnd().getLine();
            int startChar = range.getStart().getCharacter();
            int endChar = range.getEnd().getCharacter();
            
            String newText = change.getText();
            String[] newLines = newText.split("\n", -1);
            
            // 构建新文本
            StringBuilder result = new StringBuilder();
            
            // 添加开始行之前的内容
            for (int i = 0; i < startLine; i++) {
                result.append(lines[i]).append("\n");
            }
            
            // 处理第一行
            if (startLine < lines.length) {
                result.append(lines[startLine].substring(0, startChar));
                result.append(newLines[0]);
            }
            
            // 添加中间行
            for (int i = 1; i < newLines.length - 1; i++) {
                result.append(newLines[i]).append("\n");
            }
            
            // 处理最后一行
            if (newLines.length > 1) {
                result.append(newLines[newLines.length - 1]);
            }
            
            // 添加结束行之后的内容
            if (endLine < lines.length) {
                result.append(lines[endLine].substring(endChar));
                for (int i = endLine + 1; i < lines.length; i++) {
                    result.append("\n").append(lines[i]);
                }
            }
            
            document.setText(result.toString());
        }
        
        private void publishDiagnostics(String uri, String text) {
            if (languageClient == null) {
                return;
            }
            
            try {
                String filePath = uriToFilePath(uri);
                String projectRoot = extractProjectRoot(uri);
                
                List<com.harmony.pilot.common.dto.Diagnostic> diagnostics = 
                    diagnosticService.checkFile(filePath, text, projectRoot);
                
                List<org.eclipse.lsp4j.Diagnostic> lspDiagnostics = diagnostics.stream()
                    .map(this::convertToLSPDiagnostic)
                    .collect(Collectors.toList());
                
                languageClient.publishDiagnostics(new PublishDiagnosticsParams(uri, lspDiagnostics));
                
            } catch (Exception e) {
                log.error("Failed to publish diagnostics", e);
            }
        }
        
        private CompletionItem convertToLSPCompletionItem(com.harmony.pilot.common.dto.CompletionItem item) {
            CompletionItem lspItem = new CompletionItem();
            lspItem.setLabel(item.getLabel());
            lspItem.setKind(convertToLSPCompletionItemKind(item.getKind()));
            lspItem.setDetail(item.getDetail());
            lspItem.setDocumentation(item.getDocumentation());
            lspItem.setInsertText(item.getInsertText() != null ? item.getInsertText() : item.getLabel());
            lspItem.setSortText(item.getSortOrder() != null ? String.format("%05d", item.getSortOrder()) : "99999");
            return lspItem;
        }
        
        private CompletionItemKind convertToLSPCompletionItemKind(String kind) {
            if (kind == null) {
                return CompletionItemKind.Text;
            }
            
            return switch (kind.toLowerCase()) {
                case "function", "method" -> CompletionItemKind.Function;
                case "class" -> CompletionItemKind.Class;
                case "variable", "field" -> CompletionItemKind.Variable;
                case "keyword" -> CompletionItemKind.Keyword;
                case "snippet" -> CompletionItemKind.Snippet;
                default -> CompletionItemKind.Text;
            };
        }
        
        private org.eclipse.lsp4j.Location convertToLSPLocation(com.harmony.pilot.common.dto.Location location) {
            org.eclipse.lsp4j.Location lspLocation = new org.eclipse.lsp4j.Location();
            lspLocation.setUri(filePathToUri(location.getFilePath()));
            
            Position start = new Position(location.getLine() - 1, location.getColumn() - 1);
            Position end = new Position(location.getLine() - 1, location.getColumn());
            lspLocation.setRange(new Range(start, end));
            
            return lspLocation;
        }
        
        private org.eclipse.lsp4j.Diagnostic convertToLSPDiagnostic(com.harmony.pilot.common.dto.Diagnostic diagnostic) {
            org.eclipse.lsp4j.Diagnostic lspDiagnostic = new org.eclipse.lsp4j.Diagnostic();
            
            Position start = new Position(diagnostic.getLine() - 1, diagnostic.getColumn() - 1);
            Position end = new Position(diagnostic.getLine() - 1, diagnostic.getColumn());
            lspDiagnostic.setRange(new Range(start, end));
            
            lspDiagnostic.setSeverity(convertToLSPDiagnosticSeverity(diagnostic.getSeverity()));
            lspDiagnostic.setMessage(diagnostic.getMessage());
            lspDiagnostic.setSource("OpenHarmony Language Server");
            
            return lspDiagnostic;
        }
        
        private DiagnosticSeverity convertToLSPDiagnosticSeverity(String severity) {
            if (severity == null) {
                return DiagnosticSeverity.Error;
            }
            
            return switch (severity.toLowerCase()) {
                case "error" -> DiagnosticSeverity.Error;
                case "warning" -> DiagnosticSeverity.Warning;
                case "info" -> DiagnosticSeverity.Information;
                case "hint" -> DiagnosticSeverity.Hint;
                default -> DiagnosticSeverity.Error;
            };
        }
        
        private String uriToFilePath(String uri) {
            // 简化实现：移除 file:// 前缀
            if (uri.startsWith("file://")) {
                return uri.substring(7);
            }
            return uri;
        }
        
        private String filePathToUri(String filePath) {
            // 简化实现：添加 file:// 前缀
            if (filePath.startsWith("file://")) {
                return filePath;
            }
            return "file://" + filePath;
        }
        
        private String extractProjectRoot(String uri) {
            // 简化实现：从URI提取项目根目录
            String filePath = uriToFilePath(uri);
            int lastSlash = filePath.lastIndexOf('/');
            if (lastSlash > 0) {
                return filePath.substring(0, lastSlash);
            }
            return "/";
        }
    }
    
    /**
     * 工作区服务实现
     */
    private class OpenHarmonyWorkspaceService implements WorkspaceService {
        
        @Override
        public void didChangeConfiguration(DidChangeConfigurationParams params) {
            log.info("Configuration changed");
        }
        
        @Override
        public void didChangeWatchedFiles(DidChangeWatchedFilesParams params) {
            log.debug("Watched files changed");
        }
        
        @Override
        public CompletableFuture<List<? extends SymbolInformation>> symbol(WorkspaceSymbolParams params) {
            
            log.debug("Workspace symbol search: {}", params.getQuery());
            
            try {
                // 从参数中提取项目根目录
                String projectRoot = extractProjectRoot(params.getQuery());
                
                // 调用导航服务
                List<NavigationService.SymbolInfo> symbols = 
                    navigationService.searchSymbols(params.getQuery(), projectRoot, 50);
                
                // 转换为LSP格式
                List<SymbolInformation> lspSymbols = symbols.stream()
                    .map(this::convertToLSPSymbolInformation)
                    .collect(Collectors.toList());
                
                return CompletableFuture.completedFuture(lspSymbols);
                
            } catch (Exception e) {
                log.error("Failed to search workspace symbols", e);
                return CompletableFuture.completedFuture(Collections.emptyList());
            }
        }
        
        private SymbolInformation convertToLSPSymbolInformation(NavigationService.SymbolInfo symbol) {
            SymbolInformation info = new SymbolInformation();
            info.setName(symbol.getName());
            info.setKind(convertToLSPSymbolKind(symbol.getKind()));
            
            if (symbol.getLocation() != null) {
                org.eclipse.lsp4j.Location location = convertToLSPLocation(symbol.getLocation());
                info.setLocation(location);
            }
            
            return info;
        }
        
        private SymbolKind convertToLSPSymbolKind(String kind) {
            if (kind == null) {
                return SymbolKind.Object;
            }
            
            return switch (kind.toLowerCase()) {
                case "function", "method" -> SymbolKind.Function;
                case "class" -> SymbolKind.Class;
                case "variable", "field" -> SymbolKind.Variable;
                case "namespace" -> SymbolKind.Namespace;
                default -> SymbolKind.Object;
            };
        }
        
        private org.eclipse.lsp4j.Location convertToLSPLocation(com.harmony.pilot.common.dto.Location location) {
            org.eclipse.lsp4j.Location lspLocation = new org.eclipse.lsp4j.Location();
            lspLocation.setUri(filePathToUri(location.getFilePath()));
            
            Position start = new Position(location.getLine() - 1, location.getColumn() - 1);
            Position end = new Position(location.getLine() - 1, location.getColumn());
            lspLocation.setRange(new Range(start, end));
            
            return lspLocation;
        }
        
        private String filePathToUri(String filePath) {
            if (filePath.startsWith("file://")) {
                return filePath;
            }
            return "file://" + filePath;
        }
        
        private String extractProjectRoot(String query) {
            // 简化实现
            return "/";
        }
    }
}

